﻿using AutoMapper;
using bigscreen_ai_demo.DB;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PropertyChanged;
using SqlSugar;
using SqlSugar.Extensions;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Policy;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace bigscreen_ai_demo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public DataVM vm = new ();

        public int InputDBTableRowId;
        public int OutPutDBTableRowId;
        public bool Inited = false;

        public IMapper mapper;
        public Storyboard signAminate;

        public Dictionary<string, MyInput> MyInputList = new Dictionary<string,MyInput>();

        public MainWindow()
        {
            Config.StaticPropertyChanged += (sender, e) =>
            {
                Console.WriteLine($"Property changed: {e.PropertyName}");
            };
            var configuration = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile<AutoMapperMappingProfile>();
            });

            mapper = configuration.CreateMapper();


            Config.Init();

            InitializeComponent();

            loader.Visibility = Visibility.Visible; 

            Switch_Btn.Visibility = Config.SXAI_Allow?Visibility.Visible:Visibility.Collapsed;
            DataContext = vm;
            //SaveJob();
            //ReadJob();

            signAminate = (Resources["signAminate"] as Storyboard)!;

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(main); i++)
            {
                // Retrieve child visual at specified index value.
                Visual childVisual = (Visual)VisualTreeHelper.GetChild(main, i);
                if (childVisual.GetType().Name == "MyInput")
                {
                    var bindProerty = BindingOperations.GetBinding(childVisual, MyInput.ValueProperty);
                    var filedKey = bindProerty.Path.Path.Replace("ModeA.", "");
                    MyInputList.Add(filedKey,(MyInput)childVisual);


                    //output 处理
                    SetInputOUTPUT(Config.OutPutKeys);
                }

            }
            Task.Run(() =>
            {

                
                    var db = new DBContext().Db;
                    try
                    {
                        InputDBTableRowId = db.Queryable<ModelA>().First().Id;
                        OutPutDBTableRowId = db.Queryable<ModelA>().First().Id;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("数据库连接或数据异常");
                        Application.Current.Shutdown();
                    }
                    ReadJob_OUTPUT();
                    _ = LoadModelA();

                Dispatcher.Invoke((Action)(() =>
                {
                    loader.Visibility = Visibility.Collapsed;
                }));
            });

        }

        void SetInputOUTPUT(IEnumerable<string> keys,bool rev=false) //rev反向
        {
            foreach (var item in MyInputList)
            {
                var s = keys.Contains(item.Key)?true:false;
                item.Value.IsOUTPUT = rev?!s:s;
            }
        }

        void MessageShow(string message,bool isDialog= false)
        {
            if (isDialog)
            {
                MessageBox.Show(message);
            }
            else
            {
            vm.ActionMessage = message + " : "+DateTime.Now.ToString("HH:mm:ss");
            this.Dispatcher.Invoke(() =>
            {
                ActionMessage.BeginStoryboard(signAminate);
            });
            }

        }

        async public Task<bool> LoadModelA() {

            try
            {
            
                var modelA = await new DBContext().Db.Queryable<ModelA>().FirstAsync();
                if (modelA!= null)
                {
                    mapper.Map(modelA,vm.ModeA = Config.ModelA_Default);
               
                }else{
                    vm.ModeA = Config.ModelA_Default;
                }

                vm.ModeA_OUTPUT = mapper.Map<ModelA_OUTPUT>(vm.ModeA);

                MyInputList.ToList().ForEach( input =>
                {
                    input.Value.Dispatcher.Invoke(() =>
                    {
                        input.Value.OldUpdated = vm.ModeA.Updated.Value;
                        input.Value.Updated = vm.ModeA.Updated.Value;
                    });


                });
                MessageShow("db input 读取成功");

            }
            catch
            {
                MessageShow("db input 读取失败");
            }
            
            return true;
        }
        async public Task<bool> LoadModelA_OUTPUT()
        {

            var modelProps = vm.ModeA_OUTPUT.GetType().GetProperties();
            Config.modelA_OUTPUT_Maps.ForEach(async (m) =>
            {
                var model = await new DBContext().Db.Queryable<ModelA_OUTPUT>().OrderByDescending(d => d.Id).FirstAsync(d => d.Type == m.Type);
                //只更新 新记录
                if (model != null && model.Updated > vm.ModeA.Updated)
                {
                    m.Keys.ForEach(k =>
                    {
                        var newValue = (string)model.GetType().GetProperty(k)!.GetValue(model);
                        if (!string.IsNullOrWhiteSpace(newValue))
                        {
                            vm.ModeA_OUTPUT.GetType().GetProperty(k)!.SetValue(vm.ModeA_OUTPUT, valueFixed(newValue));
                            
                            MyInputList[k].Dispatcher.Invoke(() =>
                            {
                                MyInputList[k].Updated = model.Updated.Value;
                            });
                        }

                    });
                }
            });


            MessageShow("db out 读取成功");


            return true;
        }
        async public Task<DateTime> SaveModelA()
        {
            var now = DateTime.Now;
            vm.ModeA.Updated = now;

            await Task.Run(() =>
            {
                vm.JobStop = true;
                new DBContext().Db.Updateable<ModelA>(vm.ModeA).Where(d => d.Id == InputDBTableRowId).ExecuteCommand();
                vm.JobStop = false;
                Dispatcher.Invoke(() =>
                {
                    saveSign.BeginStoryboard(signAminate);
                });
            });
            return now;
        }
        public void SaveJob()
        {
            Task.Run(async () =>
            {
                if (!vm.JobStop)
                {
                    var _ = SaveModelA().ContinueWith( t =>
                    {
                        Dispatcher.Invoke(() =>
                        {
                            saveSign.BeginStoryboard(signAminate);
                        });
                       
                    });
                }
                await Task.Delay(Config.SaveJobTime);
                SaveJob();
            });


        }
        public void ReadJob_OUTPUT()
        {
            Task.Run(async () =>
            {
                if (!vm.JobStop)
                {
                        var __ = LoadModelA_OUTPUT().ContinueWith(t =>
                        {
                            try
                            {
                                if (t.Result == true)
                                {
                                    Dispatcher.Invoke(() => 
                                    {
                                        Console.WriteLine("readSign");
                                        readSign.BeginStoryboard(signAminate);
                                    });
                                   
                                    //act
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageShow("db output 读失败");
                            }
                        });
                }
                await Task.Delay(Config.ReadJobTime);
                ReadJob_OUTPUT();
            });


        }

        private void Button_Reg(object sender, RoutedEventArgs e)
        {
            URLProtocol.Reg();
        }

        private void Button_UnReg(object sender, RoutedEventArgs e)
        {
            URLProtocol.UnReg();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            main.Visibility = main.Visibility == Visibility.Visible ? Visibility.Hidden : Visibility.Visible;
        }


        static string valueFixed(string newValue)
        {
            var d = Convert.ToDecimal(newValue);
            var newValueFixed = decimal.Parse(d.ToString("0.######"), CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture);
            return newValueFixed;
        }

        private  async void Changed(object sender, RoutedEventArgs e)
        {
            //vm.ModeA.Created = DateTime.Now;

            //vm.ModeA.Updated = DateTime.Now;

            //await Task.Run(() =>
            //{
            //    vm.JobStop = true;
            //    writeDB.Updateable(vm.ModeA).Where(d => d.Id == writeDBTableRowId).ExecuteCommand();
            //    readDB.Updateable<ModelA_OUTPUT>(vm.ModeA).Where(d => d.Id == readDBTableRowId).ExecuteCommand();
            //    vm.JobStop = false;
            //});

        }

        private void Close(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();   
        }

        private async void Submit(object sender, RoutedEventArgs e)
        {
            //将输入值更新到旧值上
            var allOutKeys= Config.modelA_OUTPUT_Maps.SelectMany(m => m.Keys).ToList();
            typeof(ModelA).GetProperties().ToList().ForEach(k =>
            {
                var inputValue = typeof(ModelA).GetProperty(k.Name).GetValue(vm.ModeA);
                var oldValue = typeof(ModelA).GetProperty(k.Name).GetValue(vm.ModeA_OUTPUT);
                if (inputValue!= oldValue)
                {
                    typeof(ModelA).GetProperty(k.Name)!.SetValue(vm.ModeA_OUTPUT, inputValue);
                }
            });

            var date = await SaveModelA();
            MyInputList.ToList().ForEach(input =>
            {
                input.Value.OldUpdated = date;
                input.Value.Updated = date;
            });

        }

        private void Apply(object sender, RoutedEventArgs e)
        {
            //vm.ModeA = mapper.Map<ModelA>(vm.ModeA_OUTPUT);
            //更新同步out
            Config.modelA_OUTPUT_Maps.ForEach(m =>
            {
                m.Keys.ForEach(k =>
                {
                    var newValue = (string)typeof(ModelA_OUTPUT).GetProperty(k)!.GetValue(vm.ModeA_OUTPUT);
                    if (!string.IsNullOrWhiteSpace(newValue))
                    {
                        typeof(ModelA).GetProperty(k)!.SetValue(vm.ModeA, newValue);
                    }
                    
                });
            });
            SaveModelA();

        }
        /// <summary>
        /// 切换模式
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Switch(object sender, RoutedEventArgs e)
        {
            Config.SXAI_Show = !Config.SXAI_Show;
            if(Config.SXAI_Show) {
                //Switch_Btn.Content = "";
                vm.JobStop = true;
                SetInputOUTPUT(Config.SXAIPostKeys, true);
            }
            else
            {
                vm.JobStop = false;
                SetInputOUTPUT(Config.OutPutKeys);
            }
            
        }

        //提交到sxai
        private async void SubmitSXAI(object sender, RoutedEventArgs e)
        {
            if (!Config.SXAI_Allow) return;
            HttpClient client = new HttpClient();
            var submitData = Config.SXAIPostKeys.ToDictionary(
                key => key+ ".PV",
                key => typeof(ModelA).GetProperty(key)?.GetValue(vm.ModeA).ObjToDecimal()
            );
            //submitData["PVF_0301.PV"] = 16.32.ObjToDecimal();
            //submitData["PVF_0302.PV"] = 36.65.ObjToDecimal();
            try { 
                var response = await client.PostAsJsonAsync(Config.SXAIPostUrl, submitData);
                var resStr = await response.Content.ReadAsStringAsync();
                // resStr = {"input_variables":{"FT_0301.PV":6.72,"FT_0302.PV":26.59,"FT_0401.PV":361.25,"LT_0301.PV":361.75,"LT_0401.PV":129.55,"LT_0601.PV":138.23,"PVF_0301.PV":16.32,"PVF_0302.PV":36.65},"predictions":{"pressure":{"PT_0301B.PV":{"std":0.0,"unit":"MPa","value":2.0120413303375244},"PT_0301D.PV":{"std":0.0,"unit":"MPa","value":2.018430709838867},"PT_0302.PV":{"std":0.0,"unit":"MPa","value":2.005842447280884},"PT_0303.PV":{"std":2.384185791015625e-07,"unit":"MPa","value":2.0673539638519287},"PT_0401.PV":{"std":0.0,"unit":"MPa","value":1.97750723361969},"PT_0402.PV":{"std":0.0,"unit":"MPa","value":2.0637152194976807},"PT_0501.PV":{"std":0.0,"unit":"MPa","value":1.9829597473144531}},"temperature":{"TT_0301A.PV":{"std":3.814697265625e-06,"unit":"\u2103","value":60.53528594970703},"TT_0301B.PV":{"std":7.62939453125e-06,"unit":"\u2103","value":75.29285430908203},"TT_0301C.PV":{"std":3.814697265625e-06,"unit":"\u2103","value":59.366172790527344},"TT_0301D.PV":{"std":0.0,"unit":"\u2103","value":72.61634063720703},"TT_0301E.PV":{"std":7.62939453125e-06,"unit":"\u2103","value":76.5996322631836},"TT_0302.PV":{"std":7.62939453125e-06,"unit":"\u2103","value":69.63987731933594},"TT_0401.PV":{"std":7.62939453125e-06,"unit":"\u2103","value":71.3906478881836},"TT_0402.PV":{"std":7.62939453125e-06,"unit":"\u2103","value":68.67853546142578},"TT_0403.PV":{"std":7.62939453125e-06,"unit":"\u2103","value":84.67655944824219},"TT_0501.PV":{"std":0.0,"unit":"\u2103","value":3.1395740509033203},"TT_0601.PV":{"std":1.9073486328125e-06,"unit":"\u2103","value":22.119144439697266}}},"status":"success"}

                var res = JsonConvert.DeserializeObject<JObject>(resStr);
                if (res["status"].ToSqlValue() == "'success'")
                {
                    // Create dictionary to store temperature values
                    var temperatureData = new Dictionary<string, decimal>();
                    var temperatures = res["predictions"]["temperature"];
                
                    foreach (JProperty temp in temperatures)
                    {
                        temperatureData[temp.Name] = temp.Value["value"].Value<decimal>();
                    }


                    ResMap(vm.ModelA_SXAI, temperatureData);
                
                    // Similarly for pressure if needed
                    var pressureData = new Dictionary<string, decimal>();
                    var pressures = res["predictions"]["pressure"];
                
                    foreach (JProperty pressure in pressures)
                    {
                        pressureData[pressure.Name] = pressure.Value["value"].Value<decimal>();
                    }
                
                    ResMap(vm.ModelA_SXAI, pressureData);

                }
                else
                {
                    MessageShow("请求失败",true);
                }
            }catch(Exception ex)
            {
                MessageShow($"Error: {ex}",true);
            }
        }

        public void ResMap(ModelA modelA,Dictionary<string,decimal> obj)
        {

            foreach (var prop in typeof(ModelA).GetProperties())
            {
                if (obj.Keys.Contains(prop.Name+".PV"))
                {
                    prop.SetValue(modelA, obj[prop.Name + ".PV"].ToString());
                }
            }
        }

        public void MapJsonToModelA(ModelA modelA, string jsonString)
        {
            /**
 样本数据: {
  "TT_0301A.PV": 54.875,
  "TT_0301B.PV": 67.125,
  "TT_0301C.PV": 52.359375,
  "TT_0301D.PV": 64.53125,
  "TT_0301E.PV": 67.578125,
  "TT_0302.PV": 60.539062,
  "TT_0401.PV": 63.257812,
  "TT_0402.PV": 58.867188,
  "TT_0403.PV": 78.515625,
  "TT_0601.PV": 29.875,
  "PT_0301B.PV": 2.026367,
  "PT_0301D.PV": 2.011719,
  "PT_0302.PV": 2.0,
  "PT_0303.PV": 2.0625,
  "PT_0401.PV": 1.997803,
  "PT_0402.PV": 2.08252,
  "PT_0501.PV": 2.016602,
  "FT_0301.PV": 0.0007,
  "FT_0302.PV": 2.464355,
  "FT_0401.PV": 346.125,
  "LT_0301.PV": 339.9375,
  "LT_0401.PV": 110.6875,
  "LT_0601.PV": 339.125,
  "PVF_0301.PV": 15.158203,
  "PVF_0302.PV": 6.674805,
  "WT_0101.PV": 146.4375,
  "PIAS_0102.PV": 0.929443,
  "PDT_0502.PV": 6.849609,
  "TT_0501.PV": 2.876465
}

             */
            var data = JsonConvert.DeserializeObject<Dictionary<string, decimal>>(jsonString);
            
            foreach (var prop in typeof(ModelA).GetProperties())
            {
                // Look for matching key in the format "PropertyName.PV"
                string pvKey = $"{prop.Name}.PV";
                if (data.ContainsKey(pvKey))
                {
                    // Convert the decimal value to string and set the property
                    prop.SetValue(modelA, data[pvKey].ToString(CultureInfo.InvariantCulture));
                }
            }
        }

        private void MapJsonToModelA_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                MapJsonToModelA(vm.ModeA, JsonInput.Text);
                MapJsonToModelA(vm.ModeA_OUTPUT, JsonInput.Text);
                vm.History.Insert(0, JsonInput.Text); // Add at beginning
                while (vm.History.Count > 5)    // Keep only last 5
                {
                    vm.History.RemoveAt(vm.History.Count - 1);
                }
            }catch (Exception ex)
            {
                MessageShow(ex.Message);
            }
        }
        private void History_ItemClick(object sender, MouseButtonEventArgs e)
        {
            if (sender is TextBlock textBlock)
            {
                string jsonText = textBlock.Text;
                MapJsonToModelA(vm.ModeA, jsonText);
                MapJsonToModelA(vm.ModeA_OUTPUT, jsonText);
                textBlock.Text = jsonText;
            }
        }
    }
    public class InvertableBooleanToVisibilityConverter : IValueConverter
    {
        enum Parameters
        {
            Normal, Inverted
        }

        public object Convert(object value, Type targetType,
                              object parameter, CultureInfo culture)
        {
            var boolValue = (bool)value;
            if(parameter == null)
            {
                parameter = "Normal";
            }
            var direction = (Parameters)Enum.Parse(typeof(Parameters), (string)parameter);

            if (direction == Parameters.Inverted)
                return !boolValue ? Visibility.Visible : Visibility.Collapsed;

            return boolValue ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            return null;
        }
    }
    public class AutoMapperMappingProfile : Profile
    {
        /// <summary>
        /// 添加映射规则
        /// </summary>
    public AutoMapperMappingProfile()
    {
            CreateMap<ModelA, ModelA>()
                .ForAllMembers(opts => opts
                    .Condition((src, dest, srcValue) => 
                        srcValue != null && 
                        (srcValue.GetType() != typeof(string) || !string.IsNullOrEmpty((string)srcValue))
                    ));
            
            CreateMap<ModelA, ModelA_OUTPUT>();
        }
    }

    [AddINotifyPropertyChangedInterface]
    public class DataVM
    {
        public string ActionMessage { get; set; } = "";
        public bool LoadingShow { get; set; } = false;
        public bool JobStop { get; set; } = false;
        public ModelA ModeA { get; set; } = new();
        public ModelA ModeA_OUTPUT { get; set; } = new();

        public ModelA ModelA_SXAI { get; set; } = new();
        public ObservableCollection<string> History { get; } = new ObservableCollection<string>();

    }

}